import { Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatSnackBarModule, MatSnackBar } from '@angular/material/snack-bar';

interface FileChunk {
  chunk: Blob;
  index: number;
  hash: string;
  progress: number;
  status: 'pending' | 'uploading' | 'success' | 'error';
}

@Component({
  selector: 'app-file-upload',
  standalone: true,
  imports: [
    CommonModule,
    MatProgressBarModule,
    MatButtonModule,
    MatIconModule,
    MatSnackBarModule
  ],
  templateUrl: './file-upload.component.html',
  styleUrl: './file-upload.component.scss'
})
export class FileUploadComponent {
  @Input() maxFileSize = 1024 * 1024 * 1024; // 默认最大1GB
  @Input() chunkSize = 1024 * 1024 * 2; // 默认分片大小2MB
  @Input() acceptedFileTypes = '*';
  @Output() uploadComplete = new EventEmitter<string>();

  file: File | null = null;
  fileChunks: FileChunk[] = [];
  uploadProgress = 0;
  isUploading = false;
  uploadSpeed = 0;
  lastUploadedAt: number = 0;
  uploadedSize = 0;

  constructor(private snackBar: MatSnackBar) {}

  onFileSelected(event: Event): void {
    const input = event.target as HTMLInputElement;
    if (input.files && input.files.length > 0) {
      this.handleFile(input.files[0]);
    }
  }

  onDrop(event: DragEvent): void {
    event.preventDefault();
    event.stopPropagation();
    if (event.dataTransfer?.files.length) {
      this.handleFile(event.dataTransfer.files[0]);
    }
  }

  onDragOver(event: DragEvent): void {
    event.preventDefault();
    event.stopPropagation();
  }

  private async handleFile(file: File): Promise<void> {
    if (!this.validateFile(file)) {
      return;
    }

    this.file = file;
    this.fileChunks = [];
    this.uploadProgress = 0;
    this.uploadedSize = 0;
    this.isUploading = false;

    await this.createFileChunks(file);
  }

  private validateFile(file: File): boolean {
    if (file.size > this.maxFileSize) {
      this.snackBar.open('文件大小超过限制', '关闭', { duration: 3000 });
      return false;
    }

    if (this.acceptedFileTypes !== '*') {
      const fileType = file.type || '';
      const acceptedTypes = this.acceptedFileTypes.split(',');
      if (!acceptedTypes.some(type => fileType.startsWith(type))) {
        this.snackBar.open('不支持的文件类型', '关闭', { duration: 3000 });
        return false;
      }
    }

    return true;
  }

  private async createFileChunks(file: File): Promise<void> {
    const chunks: FileChunk[] = [];
    const chunkCount = Math.ceil(file.size / this.chunkSize);

    for (let i = 0; i < chunkCount; i++) {
      const start = i * this.chunkSize;
      const end = Math.min(start + this.chunkSize, file.size);
      const chunk = file.slice(start, end);
      const chunkHash = await this.calculateHash(chunk);

      chunks.push({
        chunk,
        index: i,
        hash: chunkHash,
        progress: 0,
        status: 'pending'
      });
    }

    this.fileChunks = chunks;
  }

  private async calculateHash(chunk: Blob): Promise<string> {
    const buffer = await chunk.arrayBuffer();
    const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
  }

  async startUpload(): Promise<void> {
    if (!this.file || this.isUploading) {
      return;
    }

    this.isUploading = true;
    this.lastUploadedAt = Date.now();
    this.uploadSpeed = 0;

    try {
      await this.uploadChunks();
      await this.mergeChunks();
      this.uploadComplete.emit(this.file.name);
      this.snackBar.open('上传完成', '关闭', { duration: 3000 });
    } catch (error) {
      console.error('Upload failed:', error);
      this.snackBar.open('上传失败', '关闭', { duration: 3000 });
    } finally {
      this.isUploading = false;
    }
  }

  private async uploadChunks(): Promise<void> {
    const uploadPromises = this.fileChunks.map(chunk => this.uploadChunk(chunk));
    await Promise.all(uploadPromises);
  }

  private async uploadChunk(chunk: FileChunk): Promise<void> {
    if (chunk.status === 'success') {
      return;
    }

    const formData = new FormData();
    formData.append('chunk', chunk.chunk);
    formData.append('index', chunk.index.toString());
    formData.append('hash', chunk.hash);
    formData.append('filename', this.file!.name);
    formData.append('totalChunks', this.fileChunks.length.toString());

    try {
      chunk.status = 'uploading';
      // 这里需要替换为实际的上传API
      const response = await fetch('/api/upload/chunk', {
        method: 'POST',
        body: formData
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      chunk.status = 'success';
      chunk.progress = 100;
      this.updateProgress();
    } catch (error) {
      chunk.status = 'error';
      throw error;
    }
  }

  private async mergeChunks(): Promise<void> {
    if (!this.file) return;

    const response = await fetch('/api/upload/merge', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        filename: this.file.name,
        totalChunks: this.fileChunks.length,
        fileHash: await this.calculateHash(this.file)
      })
    });

    if (!response.ok) {
      throw new Error('Failed to merge chunks');
    }
  }

  private updateProgress(): void {
    const successChunks = this.fileChunks.filter(chunk => chunk.status === 'success');
    const totalProgress = successChunks.length / this.fileChunks.length * 100;
    this.uploadProgress = Math.round(totalProgress);

    const currentTime = Date.now();
    const timeElapsed = (currentTime - this.lastUploadedAt) / 1000; // 转换为秒
    if (timeElapsed > 0) {
      const newUploadedSize = successChunks.length * this.chunkSize;
      const uploadedDiff = newUploadedSize - this.uploadedSize;
      this.uploadSpeed = uploadedDiff / timeElapsed; // 字节/秒
      this.uploadedSize = newUploadedSize;
      this.lastUploadedAt = currentTime;
    }
  }

  formatSpeed(): string {
    if (this.uploadSpeed === 0) return '0 KB/s';
    if (this.uploadSpeed < 1024) return `${Math.round(this.uploadSpeed)} B/s`;
    if (this.uploadSpeed < 1024 * 1024) return `${Math.round(this.uploadSpeed / 1024)} KB/s`;
    return `${Math.round(this.uploadSpeed / (1024 * 1024))} MB/s`;
  }

  cancelUpload(): void {
    this.isUploading = false;
    this.file = null;
    this.fileChunks = [];
    this.uploadProgress = 0;
    this.uploadSpeed = 0;
  }
}